package com.xlh.service.course.impl;

import com.google.common.collect.Lists;
import com.xlh.dao.course.TechnologyMapper;
import com.xlh.dao.course.ext.TechnologyMapperExt;
import com.xlh.dto.course.*;
import com.xlh.enums.course.ChapterConvertTypeEnum;
import com.xlh.enums.course.CourseSharedEnum;
import com.xlh.enums.course.UserCourseStatusEnum;
import com.xlh.enums.user.EventCodeEnum;
import com.xlh.exception.common.BadRequestException;
import com.xlh.exception.common.GlobalException;
import com.xlh.exception.common.NotFoundException;
import com.xlh.param.course.TechnologyParam;
import com.xlh.pojo.course.Technology;
import com.xlh.pojo.course.TechnologyExample;
import com.xlh.security.UserInfoHolder;
import com.xlh.service.course.ChapterService;
import com.xlh.service.course.CourseService;
import com.xlh.service.course.TechnologyService;
import com.xlh.service.courseTest.QuestionRepositoryService;
import com.xlh.service.system.OperationService;
import com.xlh.util.BeanUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 技能
 * <p>
 * Created by lx on 2019/1/28.
 */
@Service
public class TechnologyServiceImpl implements TechnologyService {

    @Autowired
    private TechnologyMapper technologyMapper;

    @Autowired
    private TechnologyMapperExt technologyMapperExt;

    @Autowired
    private ChapterService chapterService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private QuestionRepositoryService questionRepositoryService;

    @Autowired
    private UserInfoHolder userInfoHolder;

    @Autowired
    private OperationService operationService;

    @Override
    public List<TechnologyDTO> listTechnology() {
        TechnologyExample example = new TechnologyExample();
        example.setOrderByClause("id DESC");
        List<Technology> technologies = technologyMapper.selectByExample(example);
        return convertTechnology(technologies);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createTechnology(TechnologyParam param) {

        // 检查技能名称是否存在，如果存在就报错
        checkTechnologyParam(null, param);

        // 将参数进行转换，然后插入到数据库中
        Technology technology = BeanUtil.transform(Technology.class, param);
        technologyMapper.insertSelective(technology);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createTechnology(List<Technology> technologies) {
        technologyMapperExt.insertBatch(technologies);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTechnology(Long id, TechnologyParam param) {

        // 检查技能名称是否存在，如果存在就报错
        checkTechnologyParam(id, param);

        // 将参数进行转换，然后插入到数据库中
        Technology technology = BeanUtil.transform(Technology.class, param);
        technology.setId(id);
        technologyMapper.updateByPrimaryKeySelective(technology);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteTechnology(List<Long> ids) {

        // 检查删除技能的参数
        checkDeleteTechnologyParam(ids);

        // 删除技能
        TechnologyExample example = new TechnologyExample();
        example.createCriteria().andIdIn(ids);
        technologyMapper.deleteByExample(example);

    }

    @Override
    public List<TechnologyDTO> queryTechnologyFrequency() {

        // 获取全部的技能标签
        List<TechnologyDTO> technologyDTOS = listTechnology();
        if (CollectionUtils.isEmpty(technologyDTOS)) return Lists.newArrayList();

        // 获取已发布的课程中章节技能信息
        List<ChapterTechnologyDTO> chapterTechnologyDTOS = queryChapterTechnology();
        if (CollectionUtils.isEmpty(chapterTechnologyDTOS)) return technologyDTOS;

        // 将章节技能转换为字符串
        String technologyIdsStr = chapterTechnologyDTOS.stream()
                .filter(chapterTechnologyDTO -> StringUtils.isNotBlank(chapterTechnologyDTO.getTechnologyIds()))
                .map(ChapterTechnologyDTO::getTechnologyIds).collect(Collectors.joining(","));

        if (StringUtils.isEmpty(technologyIdsStr)) return technologyDTOS;

        // 统计章节技能的使用次数
        Map<Long, Long> technologyMap = Arrays.stream(technologyIdsStr.split(","))
                .map(Long::valueOf).collect(Collectors.groupingBy(p -> p, Collectors.counting()));
        if (MapUtils.isEmpty(technologyMap)) return technologyDTOS;

        // 转换结果集
        return convertTechnology(technologyDTOS, technologyMap);
    }

    @Override
    public List<Technology> listTechnology(List<Long> ids) {
        TechnologyExample example = new TechnologyExample();
        example.setOrderByClause("id DESC");
        example.createCriteria().andIdIn(ids);
        return technologyMapper.selectByExample(example);
    }

    @Override
    public ChapterTechnologyIndexDTO queryTechnologyChapter(Long id) {

        // 检查参数并获取技能信息
        Technology technology = checkAndGetTechnology(id);

        // 获取章节技能数据
        List<ChapterTechnologyDTO> chapterTechnologyDTOS = getChapterTechnology(id);

        // 获取章节结果集
        List<ChapterBasicDTO> chapterBasicDTOS = BeanUtil.batchTransform(ChapterBasicDTO.class, chapterTechnologyDTOS);
        chapterBasicDTOS = chapterBasicDTOS.stream()
                .filter(chapterBasicDTO -> Objects.equals(chapterBasicDTO.getFalg(), 0)).collect(Collectors.toList());

        // 随堂练习是否存在
        List<Long> chapterIds = chapterBasicDTOS.stream()
                .map(ChapterBasicDTO::getId).distinct().collect(Collectors.toList());
        Map<Long, Boolean> practiceExistMap = questionRepositoryService.getExistMap(chapterIds);

        // 获取已经学习的章节id集合
        List<Long> studiedChapterIds = operationService.queryOperationIds(
                userInfoHolder.getUserId(), chapterIds, EventCodeEnum.CHAPTER_STUDIED);

        // 转换章节数据
        chapterBasicDTOS = chapterService.convertChapterBasic(ChapterConvertTypeEnum.TECHNOLOGY,
                chapterBasicDTOS, UserCourseStatusEnum.FORBIDDEN, studiedChapterIds,
                practiceExistMap, null, null, null, null);

        // 转换最终结果集
        return convertChapterTechnology(chapterBasicDTOS, technology);

    }

    private ChapterTechnologyIndexDTO convertChapterTechnology(List<ChapterBasicDTO> data, Technology technology) {
        // 将值放到结果集中
        ChapterTechnologyIndexDTO result = BeanUtil.transform(ChapterTechnologyIndexDTO.class, technology);
        result.setChapterInfo(data);
        return result;
    }

    private Technology checkAndGetTechnology(Long id) {
        if (id == null) throw new BadRequestException("");
        Technology technology = technologyMapper.selectByPrimaryKey(id);
        if (technology == null) {
            throw new BadRequestException();
        }
        return technology;
    }

    private List<ChapterTechnologyDTO> getChapterTechnology(Long id) {
        // 获取章节技能数据
        List<ChapterTechnologyDTO> chapterTechnologyDTOS = queryChapterTechnology();
        if (CollectionUtils.isEmpty(chapterTechnologyDTOS)) {
            throw new NotFoundException("");
        }

        List<ChapterTechnologyDTO> parentChapters = chapterTechnologyDTOS.stream()
                .filter(chapterTechnologyDTO -> {
                    if (StringUtils.isEmpty(chapterTechnologyDTO.getTechnologyIds())) {
                        return false;
                    }
                    List<Long> ids = Arrays.stream(chapterTechnologyDTO.getTechnologyIds().split(","))
                            .map(Long::valueOf).collect(Collectors.toList());
                    return ids.contains(id);
                }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(parentChapters)) {
            throw new NotFoundException("");
        }

        // 将子章节进行过滤并添加到结果集中
        List<Long> chapterIds = parentChapters.stream().map(ChapterTechnologyDTO::getId).collect(Collectors.toList());
        parentChapters.addAll(
                chapterTechnologyDTOS.stream()
                        .filter(chapterTechnologyDTO -> chapterTechnologyDTO.getParentId() != null
                                && chapterIds.contains(chapterTechnologyDTO.getParentId()))
                        .collect(Collectors.toList())
        );

        return parentChapters;
    }

    /**
     * 转换技能结果集
     *
     * @param technologyDTOS 需要转换的对象
     * @param technologyMap  技能使用频率集合
     * @return
     */
    private List<TechnologyDTO> convertTechnology(List<TechnologyDTO> technologyDTOS, Map<Long, Long> technologyMap) {
        technologyDTOS.forEach(technologyDTO -> {
            Long num = technologyMap.get(technologyDTO.getId());
            if (num != null) {
                technologyDTO.setUseNum(num);
            }
        });
        return technologyDTOS;
    }

    private void checkDeleteTechnologyParam(List<Long> ids) {

        if (CollectionUtils.isEmpty(ids)) {
            throw new BadRequestException("请选择需要删除的技能");
        }

        List<Technology> technologies = listTechnology(ids);
        if (CollectionUtils.isEmpty(technologies)) {
            throw new BadRequestException("请选择需要删除的技能");
        }

        ids = technologies.stream().map(Technology::getId).collect(Collectors.toList());

        // 查询被删除的id集合，是不是有章节在使用。
        List<Long> existTechnologyIds = chapterService.existTechnologyIds(ids);
        if (CollectionUtils.isNotEmpty(existTechnologyIds) && CollectionUtils.containsAny(ids, existTechnologyIds)) {
            throw new GlobalException("技能已被使用，暂时无法删除");
        }

    }

    private void checkTechnologyParam(Long id, TechnologyParam param) {

        // 编辑的时候，才会传id，此时查询当前id是否存在
        if (id != null) {
            Technology technology = technologyMapper.selectByPrimaryKey(id);
            if (technology == null) {
                throw new BadRequestException("技能不存在");
            }
        }

        // 检查技能名称是否重复
        TechnologyExample example = new TechnologyExample();
        TechnologyExample.Criteria criteria = example.createCriteria();
        criteria.andNameEqualTo(param.getName());
        if (id != null) {
            criteria.andIdNotEqualTo(id);
        }
        List<Technology> data = technologyMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(data)) {
            throw new BadRequestException("技能名称重复");
        }

    }

    private List<TechnologyDTO> convertTechnology(List<Technology> technologies) {
        return BeanUtil.batchTransform(TechnologyDTO.class, technologies);
    }

    private List<ChapterTechnologyDTO> queryChapterTechnology() {
        // 获取全部已发布的课程
        List<CourseDTO> courseDTOS = courseService.listCourse(CourseSharedEnum.ALL);
        if (CollectionUtils.isEmpty(courseDTOS)) return null;

        // 根据课程id获取章节信息
        List<Long> courseIds = courseDTOS.stream().map(CourseDTO::getId).collect(Collectors.toList());
        List<ChapterBasicInfoDTO> data = chapterService.queryChapterTechnology(courseIds);

        if (CollectionUtils.isEmpty(data)) return null;

        // 过滤重复的chapter_basic_id
        List<ChapterTechnologyDTO> chapterTechnologyDTOS = BeanUtil.batchTransform(ChapterTechnologyDTO.class, data);
        return chapterTechnologyDTOS.stream()
                .filter(chapterTechnologyDTO -> Objects.equals(chapterTechnologyDTO.getFalg(), 0))
                .collect(Collectors.toList());
    }

}
